package com.rr.sc.dao.impl.hibernate;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import com.rr.sc.dao.TransactionDao;
import com.rr.sc.model.Transaction;
import com.rr.sc.model.enums.TransactionType;
import com.rr.sc.utils.DateUtils;

@Repository
public class TransactionDaoImpl extends AbstractDao implements TransactionDao {
    public void saveOrUpdate(Transaction transaction) {
	getCurrentSession().saveOrUpdate(transaction);
	getCurrentSession().flush();
	getCurrentSession().evict(transaction);
    }

    public Transaction get(Long id) {
	return (Transaction) getCurrentSession().get(Transaction.class, id);
    }

    public void delete(Transaction transaction) {
	getCurrentSession().delete(transaction);
    }

    @SuppressWarnings("unchecked")
    public List<Transaction> getByUserIds(List<Long> userIds) {
	if (userIds != null && userIds.size() > 0) {
	    return find("from Transaction t where t.user.id in (?)", userIds);
	} else {
	    return find("from Transaction t where t.user.id is null");
	}
    }

    @SuppressWarnings("unchecked")
    public List<Transaction> getFiltered(List<Long> userIds, int month, int year, TransactionType transactionType, Long categoryId, Long accountId,
	    String currencyId) {
	if (CollectionUtils.isEmpty(userIds)) {
	    return null;
	}

	/*
	Criteria criteria = getCurrentSession().createCriteria(Transaction.class);

	criteria.add(Restrictions.in("user.id", userIds));
	if (month != 0 && year != 0) {
	    criteria.add(Restrictions.gt("date", DateUtils.getStartDate(year, month)));
	    criteria.add(Restrictions.lt("date", DateUtils.getEndDate(year, month)));
	}
	if (transactionType != null) {
	    criteria.add(Restrictions.eq("type", transactionType));
	}
	if (categoryId != null) {
	    criteria.add(Restrictions.eq("category.id", categoryId));
	}
	if (accountId != null) {
	    criteria.add(Restrictions.eq("account.id", accountId));
	}
	if (currencyId != null) {
	    criteria.add(Restrictions.eq("account.currency", currencyId));
	}

	criteria.addOrder(Order.asc("date"));

	return criteria.list();
	*/

	StringBuilder sb = new StringBuilder();
	sb.append(" from Transaction t ");
	sb.append(" where t.user.id in (:userIds) ");
	if (month != 0 && year != 0) {
	    sb.append(" and t.date >= :startDate ");
	    sb.append(" and t.date <= :endDate ");
	}
	if (transactionType != null) {
	    sb.append(" and t.type = :transactionType ");
	}
	if (categoryId != null) {
	    sb.append(" and t.category.id = :categoryId ");
	}
	if (accountId != null) {
	    sb.append(" and t.account.id = :accountId ");
	}
	if (currencyId != null) {
	    sb.append(" and t.account.currency.id = :currency ");
	}

	sb.append(" order by t.date, t.id ");

	Query query = getCurrentSession().createQuery(sb.toString());

	query.setParameterList("userIds", userIds);
	if (month != 0 && year != 0) {
	    query.setTimestamp("startDate", DateUtils.getStartDate(year, month));
	    query.setTimestamp("endDate", DateUtils.getEndDate(year, month));
	}
	if (transactionType != null) {
	    query.setParameter("transactionType", transactionType);
	}
	if (categoryId != null) {
	    query.setLong("categoryId", categoryId);
	}
	if (accountId != null) {
	    query.setLong("accountId", accountId);
	}
	if (currencyId != null) {
	    query.setParameter("currency", currencyId);
	}
	return query.list();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Transaction> searchDoubledTransaction(Transaction transaction) {
	Criteria criteria = getCurrentSession().createCriteria(Transaction.class);

	if (transaction.getId() != null) {
	    criteria.add(Restrictions.ne("id", transaction.getId()));
	}
	criteria.add(Restrictions.eq("user.id", transaction.getUser().getId()));
	criteria.add(Restrictions.eq("date", transaction.getDate()));
	criteria.add(Restrictions.eq("value", transaction.getValue()));
	criteria.add(Restrictions.eq("details", transaction.getDetails()));
	criteria.add(Restrictions.eq("account.id", transaction.getAccount().getId()));

	return criteria.list();
    }
}
